package com.sx.mvvmlibs.http

import android.net.ParseException
import androidx.annotation.CallSuper
import androidx.core.view.isEmpty
import androidx.core.view.isNotEmpty
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.ThreadUtils
import com.google.gson.JsonParseException
import com.google.gson.stream.MalformedJsonException
import com.lxj.xpopup.core.BasePopupView
import com.lxj.xpopup.impl.ConfirmPopupView
import com.sx.mvvmlibs.base.BaseViewModel
import com.sx.mvvmlibs.bus.RxBus
import com.sx.mvvmlibs.event.HttpEvent
import com.sx.mvvmlibs.http.impl.IBaseResponse
import com.sx.mvvmlibs.utils.Logs
import io.reactivex.rxjava3.observers.DisposableObserver
import okhttp3.ResponseBody
import org.json.JSONException
import org.json.JSONObject
import org.koin.android.ext.android.inject
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.qualifier.named
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList


/**
 * @Author: YY
 * @Date: 2022/1/11
 * @Describe: 通用的 Rx 网络请求订阅接口
 */
abstract class CommonObserverNull<T, VM : BaseViewModel<*>?>(
    private var viewModel: VM? = null,
    private var isShowDialog: Boolean = false, //是否显示加载弹窗
) : DisposableObserver<IBaseResponse<T>>(), KoinComponent {

    private val mPopMap: ConcurrentHashMap<Int, BasePopupView> by inject(named("pop_map"))

    private val approvedPopView: BasePopupView by inject(named("not_approved"))
    private val loginPopView: BasePopupView by inject(named("token_login"))
    private val NotMoneyView: BasePopupView by inject(named("not_money"))
    private val NotPaywordView: BasePopupView by inject(named("not_payword"))

    // 结果集
    lateinit var mBaseResult: IBaseResponse<T>

    /**
     * 发起网络请求
     */
    override fun onStart() {
        // 检查网络连接
        if (!NetworkUtils.isConnected()) {
            onComplete()
            return
        }

        if (viewModel != null && isShowDialog) {
            viewModel!!.showLoadingDialog()
        }
    }

    /**
     * 响应请求结果
     */
    @CallSuper
    override fun onNext(entity: IBaseResponse<T>) {
        mBaseResult = entity
        val code = entity.code()
        val msg = entity.msg()
        // 防止状态码为 null
        if (code == null) {
            onFailed(HttpProcessor.entityCodeNullable, "实体状态码为 null")
            return
        }
        // 请求成功
        if (code == ResultEnum.SUCCESS.code) {
            // 回调成功
            onSuccess()
            onResult(entity.data())
        } else {
            if (code == ResultEnum.UNAUTHORIZED.code) {
                Logs.d("401 ${ResultEnum.UNAUTHORIZED.msg}")
                if (mPopMap.isEmpty()) {
                    // 避免并发请求下弹出多次
                    mPopMap[0] = loginPopView
                    mPopMap[0]?.show()
                }else {
                    val basePopupView = mPopMap[0]
                    basePopupView?.show()
                }
            } else if (code == ResultEnum.NOT_APPROVED.code) {
                Logs.d("402 ${ResultEnum.NOT_APPROVED.msg}")
                if (mPopMap.isEmpty()) {
                    // 避免并发请求下弹出多次
                    mPopMap[0] = approvedPopView
                    mPopMap[0]?.show()
                }else {
                    val basePopupView = mPopMap[0]
                    basePopupView?.show()
                }
            }else if (code == ResultEnum.NOT_SET_PAYWORD.code) {
                Logs.d("202 ${ResultEnum.NOT_SET_PAYWORD.msg}")
                if (mPopMap.isEmpty()) {
                    // 避免并发请求下弹出多次
                    mPopMap[0] = NotPaywordView
                    mPopMap[0]?.show()
                }else {
                    val basePopupView = mPopMap[0]
                    basePopupView?.show()
                }
            } else if (code == ResultEnum.NOT_MONEY.code) {
                Logs.d("203 ${ResultEnum.NOT_MONEY.msg}")
                if (mPopMap.isEmpty()) {
                    // 避免并发请求下弹出多次
                    mPopMap[0] = NotMoneyView
                    mPopMap[0]?.show()
                }else {
                    val basePopupView = mPopMap[0]
                    basePopupView?.show()
                }
            }
            // 失败了
            onFailed(code, msg)
        }

    }

    /**
     * 请求失败
     */
    @CallSuper
    override fun onError(e: Throwable) {
        val msg: String? = if (e is HttpException) {
            var message = ""
            when (e.code()) {
                401 -> {
                    Logs.d("401 ${e.message.toString()}")
                }
                else -> {
                    try {
                        val responseBody: ResponseBody = e.response()!!.errorBody()!!
                        val jsonObject = JSONObject(responseBody.string())
                        message = jsonObject.get("message") as String
                    } catch (e: Exception) {
                        Logs.d(e.message.toString())
                    }
                }
            }
//            val s = when (e.code()) {
//                403 -> "403 请求被拒绝"
//                404 -> "404 服务器无响应 "
//                408 -> "408 服务器执行超时 "
//                500 -> "500 服务器错误，请联系管理员"
//                503 -> "503 服务器不可用"
//                else -> "网络错误"
//            }
            return onFailed(e.code(), message)
        } else if (e is SocketTimeoutException) {
            "连接超时"
        } else if (e is ConnectException) {
            "连接失败, 请检查网络"
        } else if (e is UnknownHostException) {
            "主机地址未知"
        } else if (e is JsonParseException
            || e is JSONException
            || e is ParseException
            || e is MalformedJsonException
        ) {
            "解析错误"
        } else if (e is IndexOutOfBoundsException) {
            "数组异常"
        } else {
            e.message
        }
        onFailed(HttpProcessor.notHttpException, msg)

    }


    /**
     * 请求成功
     * TODO: 不管结果的，服务器已经给出反应
     */
    open fun onSuccess() {
    }

    /**
     * 请求成功且有结果了
     * TODO：即状态码为成功的 且有数据了
     */
    abstract fun onResult(result: T?)

    /**
     * 请求失败
     */
    @CallSuper
    open fun onFailed(code: Int, msg: String?) {
        onComplete()
    }

    /**
     * 请求完成，不管是成功还是失败
     */
    override fun onComplete() {
        if (viewModel != null && isShowDialog) {
            viewModel!!.dismissLoadingDialog()
        }
    }

}